home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 4 / Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso / Pearls / texmf / source / TeX / common / texmf.c < prev    next >
C/C++ Source or Header  |  1994-04-12  |  22KB  |  918 lines

  1. /* Hand-coded routines for TeX or Metafont in C.  This code was (mostly)
  2.    written by Tim Morgan, drawing from other Unix ports of TeX.  The
  3.    file-opening routines are also used by BibTeX.  */
  4.  
  5. /* Either `texd.h' or `mfd.h' will include `../common/texmf.h'.  */
  6.  
  7. #ifdef AMIGA
  8. #include <exec/types.h>
  9. #include <workbench/startup.h>
  10. /*#include <dos/dos.h>*/
  11. #include <clib/dos_protos.h>
  12. #include <pragmas/dos_pragmas.h>
  13. extern struct DosLibrary    *DOSBase;
  14. long __stack = 20480;            /* wenigstens 20kB stack! */
  15. #endif
  16.  
  17.  
  18. /* Instantiate data in `texd.h' or `mfd.h' here.  */
  19. #define    EXTERN
  20.  
  21. #ifdef TeX
  22. #include "texd.h"
  23. #define dump_default_var TEXformatdefault
  24. #define dump_default " plain.fmt"
  25. #define dump_format " %s.fmt"
  26. #define dump_ext_length 4
  27. #define dump_default_length formatdefaultlength
  28. #define virgin_program "virtex"
  29. #define main_program texbody
  30. #define edit_value tex_edit_value
  31. #ifdef AMIGA
  32. # define edit_var ((do_rexx) ? "TEXREXXEDIT" : "TEXEDIT")
  33. #else
  34. # define edit_var "TEXEDIT"
  35. #endif
  36. #else /* not TeX */
  37. #include "mfd.h"
  38. #define dump_default_var MFbasedefault
  39. #define dump_default " plain.base"
  40. #define dump_format " %s.base"
  41. #define dump_ext_length 5
  42. #define dump_default_length basedefaultlength
  43. #define virgin_program "virmf"
  44. #define main_program main_body
  45. #define edit_value mf_edit_value
  46. #define edit_var "MFEDIT"
  47. #endif /* not TeX */
  48.  
  49. /* Catch interrupts.  */
  50. #define    HANDLE_INTERRUPTS
  51.  
  52. #ifdef HANDLE_INTERRUPTS
  53. # ifndef AMIGA
  54. #  ifdef _POSIX_SOURCE
  55. #   include <sys/types.h>
  56. #  endif
  57. #  include <signal.h>
  58. # endif
  59. #endif
  60.  
  61. #ifdef AMIGA
  62. # include <stddef.h>
  63. # include <stdlib.h>
  64. extern int do_rexx;        /* work with rexx ?? */
  65. int call_rexx(char *str);
  66. void main(int argc, char *argv[]);
  67. #endif
  68.  
  69. #ifdef BSD
  70. void funny_core_dump ();
  71. #include <sys/time.h>
  72. #include <sys/wait.h>
  73. #include <sys/file.h>
  74. #include <fcntl.h>
  75. #else
  76. #include <time.h>
  77. #endif
  78.  
  79. #if defined (BSD) || defined (SYSV)
  80. #include <sgtty.h>
  81. #endif
  82.  
  83. #ifdef atarist
  84. #include <limits.h>    /* for LONG_MIN */
  85. #include <stdlib.h>
  86. #endif
  87.  
  88. #include <ctype.h>        /* for tolower() */
  89.  
  90.  
  91. #ifndef AMIGA
  92. extern long time ();
  93. extern struct tm *localtime ();
  94. #endif
  95.  
  96.  
  97. #if defined(atarist) && defined(__GNUC__)
  98.     /* make _stksize explicit, thus we can change it later in
  99.      * the executable program.  As default, take all of the mem.
  100.      */
  101. long _stksize = -1L;
  102.  
  103.     /* d:    allow pseudo devices like /dev/A for a:
  104.      * /:    allow '/' and '\'
  105.      * (b):    open files in binary (this is done with an explicit
  106.      *    _binmode call later).
  107.      */
  108. char *_default_unixmode = "d/";
  109. #endif
  110.  
  111.  
  112. /* The main program, etc.  */
  113.  
  114. /* What we were invoked with. */
  115. static int gargc;
  116. static char **gargv;
  117.  
  118. #ifdef atarist
  119. long crlfflag;        /* write \n as \r\n in textfiles ? */
  120. #endif
  121.  
  122.  
  123.  
  124. /* The entry point: set up for reading the command line, which will
  125.    happen in `topenin', then call the main body.  */
  126. void
  127. main (ac, av)
  128.   int ac;
  129.   char *av[];
  130. {
  131. #ifndef INI
  132.   char custom_default[FILENAMESIZE];
  133. #endif
  134. #ifdef TEXCONFIG
  135.   char *config_path;
  136.   char debugflag;
  137.   long tmp_user_language;
  138. #endif
  139. #ifdef AMIGA
  140.   char *env;
  141. #endif
  142.  
  143. #ifdef atarist
  144.   /* All files should be opened in binary mode.  The quick solution,
  145.    * using 'b' in UNIXMODE is not sufficient.
  146.    */
  147.   _binmode(1);            /* open all files in binary mode */
  148.   _mallocChunkSize(1024L);
  149. #endif
  150.  
  151. #ifdef AMIGA
  152.   if (ac == 0) {
  153.     /* Start from Workbench */
  154.     struct WBStartup *WBenchMsg = (struct WBStartup *)av;
  155.     struct WBArg *arg;
  156.  
  157.     av = (void *)xmalloc(2*sizeof(char *));    /* soviel brauch ich maximal */
  158.  
  159.     arg = WBenchMsg->sm_ArgList;
  160.     av[0] = arg->wa_Name;        /* Name ohne Pfad */
  161.  
  162.     if (WBenchMsg->sm_NumArgs > 1) {    /* gibt es auch noch ein Argument? */
  163.       arg++;
  164.       av[1] = arg->wa_Name;
  165.       (void)CurrentDir(arg->wa_Lock);    /* gehe in das Verzeichniss des Arguments */
  166.       ac = 2;
  167.     } else {
  168.       ac = 1;
  169.     }
  170.   }
  171. #endif
  172.  
  173.   dump_default_var = dump_default;
  174.   dump_default_length = strlen (dump_default) - 1;    /* lc bug */
  175.  
  176.  
  177. #ifndef INI
  178.   if (readyalready != 314159) {
  179.       char *program_name = NULL;
  180.  
  181.       program_name = rindex (av[0], '/');
  182. #ifdef atarist
  183.       if (program_name == NULL)
  184.     program_name = rindex (av[0], '\\');
  185. #endif
  186. #ifdef AMIGA
  187.       if (program_name == NULL)
  188.     program_name = index (av[0], ':');
  189. #endif
  190.       if (program_name == NULL)
  191.     program_name = av[0];
  192.       else
  193.     program_name++;
  194. #ifdef atarist
  195.       { char *suffix = rindex (program_name, '.');
  196.     if( suffix != NULL )
  197.        *suffix = '\0';
  198.       }
  199. #endif
  200.       if (strcmp (program_name, virgin_program) != 0) {
  201.           /* TeX or Metafont adds the space at the end of the name.  */
  202.           (void) sprintf (custom_default, dump_format, program_name);
  203.           dump_default_var = custom_default;
  204.           dump_default_length = strlen (program_name) + dump_ext_length;
  205.       }
  206. #ifdef AMIGA
  207.       if ((env = getenv("TEXFORMAT")) != NULL) {
  208.           (void) sprintf (custom_default, dump_format, env);
  209.           dump_default_var = custom_default;
  210.           dump_default_length = strlen (env) + dump_ext_length;
  211.       }
  212. #endif
  213.   }
  214. #endif /* not INI */
  215.  
  216.  
  217. #ifdef TEXCONFIG
  218. #ifdef atarist
  219.   crlfflag = 0L;
  220. #endif
  221.   config_path = TEXCONFIG;
  222.   debugflag = 0;
  223.   tmp_user_language = LONG_MIN;
  224.  
  225.   user_language    = -1L; /* -1 means: don't overwrite language in fmt-File */
  226.   user_interaction = -1; /* -1 means: `interaction' not set by user */
  227.  
  228. #ifdef MLTEX
  229.   is_ML_TeX = 0;
  230. #endif
  231. #ifdef TEXXET
  232.   is_TeX_XeT = 0;
  233. #endif
  234.  
  235.   while( ac > 1  && av[1][0] == '-' ) {
  236.     switch( tolower(av[1][1]) ) {
  237.     case 'c':    config_path = &av[1][2];
  238.         break;
  239.     case 'd':    debugflag++;
  240.         break;
  241. #ifdef atarist
  242.     case 't':    crlfflag=1L;        /* output \n as \r\n */
  243.         break;
  244. #endif
  245.     case 'b':    user_interaction = batchmode ;
  246.         break;
  247.     case 'n':    user_interaction = nonstopmode ;
  248.         break;
  249.     case 's':    user_interaction = scrollmode ;
  250.         break;
  251.     case 'e':    user_interaction = errorstopmode ;
  252.         break;
  253.     case 'l':    tmp_user_language = strtol(&av[1][2], NULL, 0);
  254.         /* if( tmp_user_language > 255 )
  255.           tmp_user_language = LONG_MIN; */
  256.         /* \language>255 is allowed in TeX ! ;-) */
  257.         break;
  258. #ifdef MLTEX
  259.     case 'm':    is_ML_TeX = 1;
  260.         break;
  261. #endif
  262. #ifdef TEXXET
  263.     case 'x':    is_TeX_XeT = 1;
  264.         break;
  265. #endif
  266.     default:    printf("Unknown flag -%c ignored\n", av[1][1]);
  267.         break;
  268.     }
  269.     ac--;
  270.     av++;
  271.   }
  272. #endif    /* TEXCONFIG */
  273.  
  274.   gargc = ac;
  275.   gargv = av;
  276.  
  277. #ifdef TEXCONFIG
  278.   do_path(TEXCONFIGPATH, config_path);
  279.   init_arrays(debugflag);
  280.  
  281.   /* overwrite user_language set in tex.cnf-file, if given in cmdline */
  282.   if( tmp_user_language != LONG_MIN )
  283.     user_language = tmp_user_language;
  284. #endif
  285.  
  286.   main_program ();
  287.   /*NOTREACHED*/
  288. }
  289.  
  290.  
  291.  
  292. /* This is supposed to ``open the terminal for input'', but what we
  293.    really do is copy command line arguments into TeX's or Metafont's
  294.    buffer, so they can handle them.  If nothing is available, or we've
  295.    been called already (and hence, gargc==0), we return with
  296.    `last=first'.  */
  297.  
  298. void
  299. topenin (void)
  300. {
  301.   register int i;
  302.  
  303.   buffer[first] = 0;    /* So the first `strcat' will work.  */
  304.  
  305.   if (gargc > 1) { /* We have command line arguments.  */
  306.      for (i = 1; i < gargc; i++) {
  307.     (void) strcat ((char *) &buffer[first], gargv[i]);
  308.         (void) strcat ((char *) &buffer[first], " ");
  309.      }
  310.      gargc = 0;    /* Don't do this again.  */
  311.   }
  312.  
  313.   /* Make `last' be one past the last non-blank character in `buffer'.  */
  314.   for (last = first; buffer[last]; ++last)
  315.      ;
  316.   for (--last; last >= first && buffer[last] == ' '; --last)
  317.      ;
  318.   last++;
  319. }
  320.  
  321.  
  322.  
  323.  
  324. #ifdef HANDLE_INTERRUPTS
  325. /* All our interrupt handler has to do is set TeX's or Metafont's global
  326.    variable `interrupt'; then they will do everything needed.  */
  327.  
  328. #ifdef AMIGA
  329.  
  330. int _CXBRK(void)        /* overwrite standard SAS/C-function */
  331. {
  332.   interrupt = 1;
  333.   return 0;
  334. }
  335.  
  336. #else /* !AMIGA */
  337.  
  338. static void
  339. interrupt_handler ()
  340. {
  341.   interrupt = 1;
  342.   (void) signal (SIGINT, interrupt_handler);
  343. }
  344. #endif /* !AMIGA */
  345.  
  346. #endif /* HANDLE_INTERRUPTS */
  347.  
  348.  
  349. /* Besides getting the date and time here, we also set up the interrupt
  350.    handler, for no particularly good reason.  It's just that since the
  351.    `fix_date_and_time' routine is called early on (section 1337 in TeX,
  352.    ``Get the first line of input and prepare to start''), this is as
  353.    good a place as any.  */
  354.  
  355. #ifdef atarist
  356. #include <osbind.h>
  357. #endif
  358.  
  359. void
  360. get_date_and_time (integer *minutes, integer *day, integer *month, integer *year)
  361. {
  362. #ifndef atarist
  363.   long clock;
  364.   struct tm *tmptr;
  365.  
  366.   clock = time ((long *) 0);
  367.   tmptr = localtime (&clock);
  368.  
  369.   *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
  370.   *day = tmptr->tm_mday;
  371.   *month = tmptr->tm_mon + 1;
  372.   *year = tmptr->tm_year + 1900;
  373. #else
  374.   /* Spart gegenueber den Lib-Funktionen Zeit und viel Platz ... */
  375.   unsigned dostime, dosdate;
  376.  
  377.   dostime = Tgettime();
  378.   dosdate = Tgetdate();
  379.  
  380.   *minutes = ((dostime >> 5) & 63) + 60 * ((short) ((dostime >> 11) & 31));
  381.   *day = dosdate & 31;
  382.   *month = ((dosdate >> 5) & 15);
  383.   *year = 1980 + ((dosdate >> 9) & 255);
  384. #endif
  385.  
  386. #ifdef HANDLE_INTERRUPTS
  387. # ifndef AMIGA
  388.   {
  389.     SIGNAL_HANDLER_RETURN_TYPE (*old_handler) ();
  390.  
  391.     if ((old_handler = signal (SIGINT, interrupt_handler)) != SIG_DFL)
  392.       (void) signal (SIGINT, old_handler);
  393.   }
  394. # endif
  395. #endif
  396. }
  397.  
  398.  
  399.  
  400. /* I/O for TeX and Metafont.  */
  401.  
  402. /* Read a line of input as efficiently as possible while still looking
  403.    like Pascal.  We set `last' to `first' and return `false' if we get
  404.    to eof.  Otherwise, we return `true' and either `last==first' or
  405.    `buffer[last-1]!=' ''; that is, last == first + length(line except
  406.    trailing whitespace).  */
  407.  
  408. boolean
  409. input_line (register FILE *f)
  410. {
  411.   register int i = EOF;
  412.   register ASCIIcode *bufp;    /* bufp = &buffer[last] */
  413.   register integer r_last;    /* register var for global `last' */
  414.   register ASCIIcode *r_bufend = &buffer[bufsize];
  415.  
  416.   r_last = first;    /* last = first;   cf. Matthew 19:30 */
  417.   bufp = &buffer[r_last];
  418.  
  419. #ifdef BSD
  420.   if (f == stdin) clearerr (stdin);
  421. #endif
  422.  
  423.   /*      last < bufsize */
  424.   while (bufp < r_bufend && (i = getc (f)) != EOF && i != '\n') {
  425.     *bufp++ = i;        /* buffer[last++] = i */
  426.   }
  427.  
  428.   r_last = bufp - buffer;
  429.  
  430.   if (i == EOF && r_last == first) {
  431.     last = r_last;
  432.     return false;
  433.   }
  434.  
  435.   /* We didn't get the whole line because our buffer was too small.  */
  436.   if (i != EOF && i != '\n') {
  437.     (void) fprintf (stderr, "\
  438. ! Unable to read an entire line---bufsize=%ld.\n\
  439. Please set `bufsize' to a larger value.\n", bufsize);
  440.       exit (10);
  441.   }
  442.  
  443.   /* buffer[last] = ' '; */
  444.   *bufp-- = ' ';    /* bufp-- because of buffer[last-1] in next loop */
  445.     
  446.   if (r_last > maxbufstack)
  447.     maxbufstack = r_last;
  448.  
  449.   /* Trim trailing whitespace.  */
  450.   while (r_last > first && (*bufp == ' ' || *bufp == '\t'
  451. #ifdef atarist
  452.   /* ... and trailing carriage returns.  */    || *bufp == '\r'
  453. #endif
  454.                                 )) {
  455.     --r_last; --bufp;
  456.   }
  457.  
  458.   last = r_last;    /* Don't forget this ! */
  459.  
  460.  
  461.   /* Now, either `last==first' or `buffer[last-1] != ' '' (or \t). */
  462.  
  463.   /* Don't bother using xord if we don't need to.  */
  464. #ifdef NONASCII
  465. #if 0
  466.   for (i = first; i <= last; i++)
  467.      buffer[i] = xord[buffer[i]];
  468. #else
  469.   r_bufend = &buffer[r_last];
  470.   for( bufp = &buffer[first] ; bufp <= r_bufend ; bufp++ )
  471.      *bufp = xord[*bufp];
  472. #endif
  473. #endif
  474.  
  475.     return true;
  476. }
  477.  
  478.  
  479. #ifdef BSD
  480. /* Clear any pending terminal input.  The usual way to do this in Unix
  481.   is to switch the terminal to get the current tty flags, set RAW mode,
  482.   then switch back to the original setting.  If the user isn't in COOKED
  483.   mode, though, this won't work.  At least, it leaves his terminal in
  484.   its original mode.  */
  485.  
  486. void
  487. bsd_clear_terminal ()
  488. {
  489.   int arg = FREAD;
  490.   (void) ioctl (fileno (stdout), TIOCFLUSH, &arg);
  491. }
  492.  
  493.  
  494. /* Cancel any output cancellation (^O) by the user.  */
  495.  
  496. void
  497. bsd_wake_up_terminal ()
  498. {
  499.   int i = LFLUSHO;
  500.   (void) ioctl (fileno (stdout), TIOCLBIC, (struct sgttyb *) &i);
  501. }
  502.  
  503. #endif /* BSD */
  504.  
  505.  
  506.  
  507. #ifndef atarist
  508. /* Diese Routine braucht man eigentlich nur fuer virtex. */
  509. /* Beim ST sollte man bei Verwendung darauf achten, dass _stksize!=-1,
  510.    da sonst kein Platz fuer Editor da ist.
  511.  */
  512.  
  513.  
  514. /* This string specifies what the `e' option does in response to an
  515.    error message.  */ 
  516. static char *edit_value = EDITOR;
  517.  
  518. /* This procedure is due to sjc@s1-c.  TeX (or Metafont) calls it when
  519.    the user types `e' in response to an error, invoking a text editor on
  520.    the erroneous source file.  FNSTART is how far into FILENAME the
  521.    actual filename starts; FNLENGTH is how long the filename is.
  522.    
  523.    See ../site.h for how to set the default, and how to override it.  */
  524.  
  525. void
  526. calledit (ASCIIcode *filename, poolpointer fnstart,
  527.       integer fnlength, integer linenumber)
  528. {
  529.   char *temp, *command;
  530.   char c;
  531.   int sdone, ddone, i;
  532.  
  533.   sdone = ddone = 0;
  534.   filename += fnstart;
  535.  
  536. #ifdef AMIGA
  537.   if (do_rexx) {
  538.     edit_value = REXXEDITOR;
  539.   } else {
  540.     edit_value = EDITOR;
  541.   }
  542. #endif
  543.  
  544. #ifdef TEXCONFIG
  545.   /* Hier sollten alle Arrays (mem, eqtb, ...) wieder freigegeben werden,
  546.      damit der Editor nicht wegen Speichermangels abbricht.
  547.      Oder besser: Der Editor soll TeX ueberlagern, also kein system()-call.
  548.   */
  549. #endif
  550.  
  551.   /* Close any open input files, since we're going to kill the job.  */
  552.   for (i = 1; i <= inopen; i++)
  553.     (void) fclose (inputfile[i]);
  554.  
  555.   /* Replace the default with the value of the appropriate environment
  556.      variable, if it's set.  */
  557.   temp = getenv (edit_var);
  558.   if (temp != NULL)
  559.     edit_value = temp;
  560.  
  561.   /* Construct the command string.  The `11' is the maximum length an
  562.      integer might be.  */
  563.   command = xmalloc ((unsigned) (strlen (edit_value) + fnlength + 11));
  564.  
  565.   /* So we can construct it as we go.  */
  566.   temp = command;
  567.  
  568. #ifdef AMIGA
  569.   if (do_rexx) {    /* Einklammern */
  570.     *temp++ = '\'';
  571.   }
  572. #endif
  573.  
  574.   while ((c = *edit_value++) != 0) {
  575.       if (c == '%') {
  576.           switch (c = *edit_value++) {
  577.         case 'd':
  578.           if (ddone) {
  579.           (void) fprintf (stderr,
  580.             "! `%%d' cannot appear twice in editor command.\n");
  581.               exit (10);
  582.           }
  583.               (void) sprintf (temp, "%ld", linenumber);
  584.               while (*temp != '\0')
  585.                 temp++;
  586.               ddone = 1;
  587.               break;
  588.  
  589.         case 's':
  590.               if (sdone) {
  591.               (void) fprintf(stderr,
  592.             "! `%%s' cannot appear twice in editor command.\n");
  593.           exit (10);
  594.           }
  595.               for (i = 0 ; i < fnlength ; i++)
  596.         *temp++ = Xchr (filename[i]);
  597.               sdone = 1;
  598.               break;
  599.  
  600.         case '\0':
  601.               *temp++ = '%';
  602.               /* Back up to the null to force termination.  */
  603.           edit_value--;
  604.           break;
  605.  
  606.         default:
  607.           *temp++ = '%';
  608.           *temp++ = c;
  609.           break;
  610.       }
  611.       } else
  612.       *temp++ = c;
  613.   }
  614.  
  615. #ifdef AMIGA
  616.   if (do_rexx) {    /* Einklammern... */
  617.     *temp++ = '\'';
  618.   }
  619. #endif
  620.  
  621.   *temp = 0;
  622.  
  623.   /* Execute the command.  */
  624. #ifdef AMIGA
  625.   if (do_rexx) {
  626.     if (!call_rexx(command))
  627.       (void) fprintf(stderr, "! Trouble executing ARexx command `%s'.\n", command);
  628.   } else {
  629.     if (system (command) != 0)
  630.       (void) fprintf(stderr, "! Trouble executing command `%s'.\n", command);
  631.   }
  632. #else
  633.   if (system (command) != 0)
  634.     (void) fprintf(stderr, "! Trouble executing `%s'.\n", command);
  635. #endif
  636.  
  637.   /* Quit, since we found an error.  */
  638.   exit (5);
  639. }
  640. #else
  641. void
  642. calledit (filename, fnstart, fnlength, linenumber)
  643.   ASCIIcode *filename;
  644.   poolpointer fnstart;
  645.   integer fnlength, linenumber;
  646. {
  647.     (void) fprintf(stderr, "! Sorry, `e' command not implemented.\n");
  648.     exit(5);
  649. }
  650. #endif
  651.  
  652.  
  653.  
  654. #ifdef BSD
  655. /* This procedure is due to chris@mimsy.umd.edu.  It makes a core dump
  656.    without any sort of error status (abort(2) does give an error status,
  657.    so we don't want to use that).  It is used only when making a preloaded
  658.    TeX from virtex, and is triggered by a magic file name requested as
  659.    input (see `open_input', above).
  660.  
  661.    This is what is known in computing circles as a hack.  */
  662.  
  663. void
  664. funny_core_dump ()
  665. {
  666.   int pid, w;
  667.   union wait status;
  668.  
  669.   switch (pid = vfork ()) {
  670.     case -1:        /* failed */
  671.       perror ("vfork");
  672.       exit (-1);
  673.       /*NOTREACHED*/
  674.  
  675.     case 0:             /* child */
  676.        (void) signal (SIGQUIT, SIG_DFL);
  677.        (void) kill (getpid (), SIGQUIT);
  678.        (void) write (2, "how did we get here?\n", 21);
  679.        _exit(1);
  680.        /*NOTREACHED*/
  681.  
  682.     default:        /* parent */
  683.       while ((w = wait (&status)) != pid && w != -1)
  684.     ;
  685.       if (status.w_coredump)
  686.     exit (0);
  687.       (void) write (2, "attempt to dump core failed\n", 28);
  688.       exit (1);
  689.     }
  690. }
  691. #endif /* BSD */
  692.  
  693.  
  694.  
  695. #ifndef TeX
  696. /* On-line display routines for Metafont.  Here we use a dispatch table
  697.    indexed by the TERM environment variable to select the graphics
  698.    routines appropriate to the user's terminal.  stdout must be
  699.    connected to a terminal for us to do any graphics.  */
  700.  
  701. /* We don't want any other window routines screwing us up if we're
  702.    trying to do the trap test.  We could have written another device for
  703.    the trap test, but the terminal type conditionals in initscreen argue
  704.    against that.  */
  705.  
  706. #ifdef TRAP
  707. #undef SUNWIN
  708. #undef HP2627WIN
  709. #undef X10WIN
  710. #undef X11WIN
  711. #undef TEKTRONIXWIN
  712. #endif
  713.  
  714.  
  715. #ifdef HP2627WIN
  716. extern mf_hp2627_initscreen (), mf_hp2627_updatescreen ();
  717. extern mf_hp2627_blankrectangle (), mf_hp2627_paintrow ();
  718. #endif
  719.  
  720. #ifdef SUNWIN
  721. extern mf_sun_initscreen (), mf_sun_updatescreen ();
  722. extern mf_sun_blankrectangle (), mf_sun_paintrow ();
  723. #endif
  724.  
  725. #ifdef TEKTRONIXWIN
  726. extern mf_tektronix_initscreen (), mf_tektronix_updatescreen ();
  727. extern mf_tektronix_blankrectangle (), mf_tektronix_paintrow ();
  728. #endif
  729.  
  730. #ifdef UNITERMWIN
  731. extern mf_uniterm_initscreen (), mf_uniterm_updatescreen();
  732. extern mf_uniterm_blankrectangle(), mf_uniterm_paintrow();
  733. #endif
  734.  
  735. #ifdef X10WIN
  736. extern mf_x10_initscreen (), mf_x10_updatescreen ();
  737. extern mf_x10_blankrectangle (), mf_x10_paintrow ();
  738. #endif
  739.  
  740. #ifdef X11WIN
  741. extern mf_x11_initscreen (), mf_x11_updatescreen ();
  742. extern mf_x11_blankrectangle (), mf_x11_paintrow ();
  743. #endif
  744.  
  745.  
  746. /* `mfwsw' contains the dispatch tables for each terminal.  We map the
  747.    Pascal calls to the routines `init_screen', `update_screen',
  748.    `blank_rectangle', and `paint_row' into the appropriate entry point
  749.    for the specific terminal that MF is being run on.  */
  750.  
  751. struct mfwin_sw
  752. {
  753.   char *mfwsw_type;        /* Name of terminal a la TERMCAP.  */
  754.   int (*mfwsw_initscreen) ();
  755.   int (*mfwsw_updatescrn) ();
  756.   int (*mfwsw_blankrect) ();
  757.   int (*mfwsw_paintrow) ();
  758. } mfwsw[] =
  759.  
  760. /* Now we have a long structure which initializes this array of
  761.    ``Metafont window switches''.  */
  762.  
  763. {
  764.  
  765. #ifdef HP2627WIN
  766.   { "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
  767.     mf_hp2627_blankrectangle, mf_hp2627_paintrow },
  768. #endif
  769.  
  770. #ifdef SUNWIN
  771.   { "sun", mf_sun_initscreen, mf_sun_updatescreen,
  772.     mf_sun_blankrectangle, mf_sun_paintrow },
  773. #endif
  774.  
  775. #ifdef TEKTRONIXWIN
  776.   { "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
  777.     mf_tektronix_blankrectangle, mf_tektronix_paintrow },
  778. #endif
  779.  
  780. #ifdef UNITERMWIN
  781.    { "uniterm", mf_uniterm_initscreen, mf_uniterm_updatescreen,
  782.      mf_uniterm_blankrectangle, mf_uniterm_paintrow },
  783. #endif
  784.  
  785. #ifdef X10WIN
  786.   { "xterm", mf_x10_initscreen, mf_x10_updatescreen,
  787.     mf_x10_blankrectangle, mf_x10_paintrow },
  788. #endif
  789.  
  790. #ifdef X11WIN
  791.   { "xterm", mf_x11_initscreen, mf_x11_updatescreen, 
  792.     mf_x11_blankrectangle, mf_x11_paintrow },
  793. #endif
  794.  
  795.   { "Irrelevant", NULL, NULL, NULL, NULL },
  796.  
  797. /* Finally, we must have an entry with a terminal type of NULL.  */
  798.   { NULL, NULL, NULL, NULL, NULL }
  799.  
  800. }; /* End of the array initialization.  */
  801.  
  802.  
  803. /* This is a pointer to current mfwsw[] entry.  */
  804. static struct mfwin_sw *mfwp;
  805.  
  806. /* The following are routines that just jump to the correct
  807.    terminal-specific graphics code. If none of the routines in the
  808.    dispatch table exist, or they fail, we produce trap-compatible
  809.    output, i.e., the same words and punctuation that the unchanged
  810.    mf.web would produce.  */
  811.  
  812.  
  813. /* This returns true if window operations legal, else false.  */
  814.  
  815. boolean
  816. initscreen ()
  817. {
  818. #ifndef TRAP
  819.   register char *ttytype;
  820.  
  821.   if ((ttytype = getenv ("TERM")) == NULL || !(isatty (fileno (stdout))))
  822.     return (0);
  823.   for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++)
  824.     if (!strncmp (mfwp->mfwsw_type, ttytype, strlen (mfwp->mfwsw_type))
  825.     || !strcmp (ttytype, "emacs"))
  826.       if (mfwp->mfwsw_initscreen)
  827.     return ((*mfwp->mfwsw_initscreen) ());
  828.       else
  829.     {            /* Test terminal type */
  830.       printf ("Could not init_screen for `%s'.\n", ttytype);
  831.       return 1;
  832.     }
  833.   return 0;
  834.  
  835. #else /* TRAP */
  836.   return 1;
  837. #endif
  838. }
  839.  
  840.  
  841. /* Make sure everything is visible.  */
  842.  
  843. void
  844. updatescreen ()
  845. {
  846. #ifndef TRAP
  847.   if (mfwp->mfwsw_updatescrn)
  848.     ((*mfwp->mfwsw_updatescrn) ());
  849.   else
  850.     {
  851.       printf ("Updatescreen called\n");
  852.     }
  853. #else /* TRAP */
  854.   fprintf (logfile, "Calling UPDATESCREEN\n");
  855. #endif
  856. }
  857.  
  858.  
  859. /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
  860.    the background color.  */
  861.  
  862. void
  863. blankrectangle (left, right, top, bottom)
  864.      screencol left, right;
  865.      screenrow top, bottom;
  866. {
  867. #ifndef TRAP
  868.   if (mfwp->mfwsw_blankrect)
  869.     ((*mfwp->mfwsw_blankrect) (left, right, top, bottom));
  870.   else
  871.     {
  872.       printf ("Blankrectangle l=%d  r=%d  t=%d  b=%d\n",
  873.           left, right, top, bottom);
  874.     }
  875. #else /* TRAP */
  876.   fprintf (logfile, "\nCalling BLANKRECTANGLE(%d,%d,%d,%d)\n", left,
  877.        right, top, bottom);
  878. #endif
  879. }
  880.  
  881.  
  882. /* This paints ROW, starting with the color INIT_COLOR. 
  883.    TRANSITION_VECTOR then specifies the length of the run; then we
  884.    switch colors.  This goes on for VECTOR_SIZE transitions.  */
  885.  
  886. void
  887. paintrow (row, init_color, transition_vector, vector_size)
  888.      screenrow row;
  889.      pixelcolor init_color;
  890.      transspec transition_vector;
  891.      screencol vector_size;
  892. {
  893. #ifndef TRAP
  894.   if (mfwp->mfwsw_paintrow)
  895.     ((*mfwp->mfwsw_paintrow) (row, init_color,
  896.                   transition_vector, vector_size));
  897.   else
  898.     {
  899.       printf ("Paintrow r=%d  c=%d  v=");
  900.       while (vector_size-- > 0)
  901.     printf ("%d  ", transition_vector++);
  902.       printf ("\n");
  903.     }
  904. #else /* TRAP */
  905.   unsigned k;
  906.  
  907.   fprintf (logfile, "Calling PAINTROW(%d,%d;", row, init_color);
  908.   for (k = 0; k <= vector_size; k++)
  909.     {
  910.       fprintf (logfile, "%d", transition_vector[k]);
  911.       if (k != vector_size)
  912.     fprintf (logfile, ",");
  913.     }
  914.   fprintf (logfile, ")\n");
  915. #endif
  916. }
  917. #endif /* not TeX */
  918.